﻿// Inner Fire 游戏引擎库
// 相机类
//
// Copyright (c) 2024 by 尔西大帝. All rights reserved.
//
// 这个文件用于各种相机。根据《DirectX12游戏开发实战》中的工具类修改。
// 原作者：Frank Luna
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-11-20

#pragma once

#include <dx/core/dx_core.h>
#include <dx/view/dx_spherical.h>

namespace ifire::dx {

enum class CameraType { NORMAL, SPHERICAL };

/// <summary>
/// 球面坐标系相机
/// </summary>
class DxSphericalCamera {
public:
  DxSphericalCamera();
  ~DxSphericalCamera() = default;

  void UpdateViewMatrix();
  DirectX::XMMATRIX GetViewMatrix() const { return view_; }
  DirectX::XMFLOAT3 GetPosition() const { return position_; }
  void OnRotate(float move_x, float move_y);
  void OnOffset(float move_x, float move_y);
  void OnWheelZoom(int delta);
  void SetCoord(float theta, float phi, float radius);
  void SetOffset(IVec3 value) { offset_ = value; }
  IVec3 GetCoord();
  IVec3 GetOffset() const { return offset_; }
  void SetRadius(float radius);

public:
  // 放大缩小的控制参数(每个滚轮单位导致的变换）
  float zoom_rate_ = 0.02f;
  // 平移的参数（每个鼠标单位能够平移的位置）
  float offset_rate_ = 0.2f;
  // 最小的半径
  float min_radius = 2.0f;
  // 最大的半径
  float max_radius = 1000.0f;

private:
  Spherical coord_;            // 使用球面坐标来表示相机
  DirectX::XMFLOAT3 position_; // 相机位置
  DirectX::XMFLOAT3 offset_;   // 相机的偏移
  DirectX::XMMATRIX view_;


};

/// <summary>
/// 标准相机
/// </summary>
class DxCamera {
public:
  DxCamera();
  ~DxCamera();

  // Get/Set相机位置
  void SetPosition(const DirectX::XMFLOAT3& v);
  const DirectX::XMFLOAT3& GetPosition() { return position_; }
  float GetAspect() const { return aspect_; }

  // 获取在视图空间坐标中近平面和远平面的尺寸。
  float GetNearWindowWidth() const { return aspect_ * near_window_height_; }
  float GetFarWindowWidth() const { return aspect_ * far_window_height_; }

  // 设置视锥体
  void SetLens(float fovY, float aspect, float zn, float zf);

  // 前进或平移相机
  void Strafe(float d);
  void Walk(float d);

  // 旋转相机
  void Pitch(float angle);
  void RotateY(float angle);

  // 通过位置和旋转来设置相机
  void SetCamera(DirectX::FXMVECTOR position, DirectX::FXMVECTOR rotation);

  // 刷新相机的矩阵。
  void UpdateViewMatrix();

  // 设置为刷新
  inline void SetRefresh() { is_dirty_ = true; }

public:
  // View/Projection矩阵缓存
  DirectX::XMFLOAT4X4 view_ = IDENTITY_4X4;
  DirectX::XMFLOAT4X4 projection_ = IDENTITY_4X4;  
  // 相对于世界空间的相机坐标系。
  DirectX::XMFLOAT3 position_ = {0.0f, 0.0f, 0.0f};
  DirectX::XMFLOAT3 right_ = {1.0f, 0.0f, 0.0f};
  DirectX::XMFLOAT3 up_ = {0.0f, 1.0f, 0.0f};
  DirectX::XMFLOAT3 look_ = {0.0f, 0.0f, 1.0f};

private:

  // 相机视椎体属性
  float near_z_ = 0.0f;
  float far_z_ = 0.0f;
  float aspect_ = 0.0f;
  float fov_y_ = 0.0f;
  float near_window_height_ = 0.0f;
  float far_window_height_ = 0.0f;

  bool is_dirty_ = true;
};

} // namespace ifire::dx